import {useNode} from "@craftjs/core";
import {ComponentType, useEffect, useState} from "react";

type TConfig = {umdUrl?: string, componentName: string, rawComponent?: ComponentType};

/** TODO: 同名情况下可能会出现问题 */
const loadUmdJs = (url: string, name: string) => {
    return new Promise<any>((rel) => {
        const script = document.createElement('script');
        script.src = url;
        script.onload = () => {
            rel((window as any)[name] ?? (window as any)['lib']);
            script.remove();
        };

        document.body.append(script);
    })
};


/**
 * 思路:
 * - umd 文件暴露 组件及 组件settings
 * - 上传umd文件,需要组件名称
 * - 获取服务器组件列表
 * - 根据列表数据,生成 craftjs 需要的组件
 */
export const loadComponents = async (configs: TConfig[]) => {
    const components = await Promise.all(configs.map(async ({umdUrl, componentName, rawComponent}) => {
        // const data = await import(umdUrl);
        let Component: ComponentType = () => <>出错了</>;
        if (umdUrl) {
            const data = await loadUmdJs(umdUrl, componentName);
            const dataKeys = Object.keys(data);

            const {MainComponent = data[dataKeys[0]] ?? (() => <>component</>), SettingsComponent = data[dataKeys[1]] ?? (() => <>settings</>)} = data;

            const InlineComponent = (props: object) => {
                const {connectors: {connect, drag}} = useNode();
                return (
                    <div ref={ref => connect(drag(ref as HTMLElement))}>
                        <MainComponent
                            {...props}
                        />
                    </div>
                )
            };

            InlineComponent.craft = {
                related: {
                    settings: SettingsComponent
                }
            };
            // console.log('loadComponents-data:', data, Object.keys(data), InlineComponent);

            Component = InlineComponent;
        }
        else if (rawComponent) {
            const InlineComponent = (props: object) => {
                const {connectors: {connect, drag}} = useNode();
                const Com = rawComponent;
                return (
                    <div ref={ref => connect(drag(ref as HTMLElement))}>
                        <Com
                            {...props}
                        />
                    </div>
                )
            };

            InlineComponent.craft = {
                related: {
                    settings: () => <>settings2</>
                }
            };

            Component = InlineComponent;
        }


        return {
            name: componentName,
            component: Component as ComponentType,
            // [componentName]: Component,
        };
    }));

    const componentsMap = components.reduce((map, ii) => {
        map[ii.name] = ii.component;
        return map;
    }, {} as Record<string, typeof components[number]['component']>);

    return {components, componentsMap};
};

let initData: Awaited<ReturnType<typeof loadComponents>> | null = null;
export const useLoadComponents = (configs?: TConfig[]) => {
    const [loading, setLoading] = useState(false);
    const [data, setData] = useState<Awaited<ReturnType<typeof loadComponents>>>(initData || {components: [], componentsMap: {}});

    const init = async () => {
        if (!configs) return;
        setLoading(true);
        const componentsData = await loadComponents(configs);
        initData = componentsData;
        setData(componentsData);
        setLoading(false);
    };

    useEffect(() => {
        if (initData) return;
        init();
    }, []);

    return {loading, ...data};
};
